]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st/theme-node-drawing: Trace the correct path for inset box shadows
authorDaniel van Vugt <daniel.van.vugt@canonical.com>
Thu, 26 Sep 2024 10:26:21 +0000 (18:26 +0800)
committerFlorian Müllner <fmuellner@gnome.org>
Thu, 17 Oct 2024 16:49:21 +0000 (18:49 +0200)
Previously we just copied the outer path and scaled it down, but that
resulted in an inconsistent thickness at the corners because the pivot
points for the arcs also moved inward.

So now we trace the inset path explicitly to maintain the correct
thickness (spread) around all the corners.

The spec actually mentions you need to do it in section 6.1 [1]:

> Note that for inner shadows, expanding the shadow (creating more
> shadow area) means contracting the shadow’s perimeter shape.

Despite the fact the example diagram gets it wrong in section 6.1.1 [2],
it does then follow with more confirmation that the shadow radius should
be reduced:

> To preserve the box’s shape when spread is applied, the corner radii
> of the shadow are also increased (decreased, for inner shadows) from
> the border-box (padding-box) radii by adding (subtracting) the spread
> distance (and flooring at zero).

[1] https://www.w3.org/TR/css-backgrounds-3/#box-shadow
[2] https://www.w3.org/TR/css-backgrounds-3/#shadow-shape

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7913
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3488>
(cherry picked from commit dde13b30c79776accf1b54fcd131441f44fc8f95)

src/st/st-theme-node-drawing.c

index 5933b3a3bc8e296d1439e026beee219ba9050dad..0b2b7b5351843bff266bce91820b527b890e2a8c 100644 (file)
@@ -909,6 +909,7 @@ static void
 paint_inset_box_shadow_to_cairo_context (StThemeNode     *node,
                                          StShadow        *shadow_spec,
                                          float            resource_scale,
+                                         const guint      outer_radius[4],
                                          cairo_t         *cr,
                                          cairo_path_t    *shadow_outline)
 {
@@ -952,10 +953,6 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode     *node,
       int surface_width = ceil ((shrunk_extents_x2 - surface_x) * resource_scale);
       int surface_height = ceil ((shrunk_extents_y2 - surface_y) * resource_scale);
 
-      /* Center of the original path */
-      double x_center = (extents_x1 + extents_x2) / 2;
-      double y_center = (extents_y1 + extents_y2) / 2;
-
       cairo_pattern_t *pattern;
       cairo_t *temp_cr;
       cairo_matrix_t matrix;
@@ -970,14 +967,67 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode     *node,
       /* Shadow offset */
       cairo_translate (temp_cr, shadow_spec->xoffset, shadow_spec->yoffset);
 
-      /* Scale the path around the center to match the shrunk bounds */
-      cairo_translate (temp_cr, x_center, y_center);
-      cairo_scale (temp_cr,
-                   (shrunk_extents_x2 - shrunk_extents_x1) / (extents_x2 - extents_x1),
-                   (shrunk_extents_y2 - shrunk_extents_y1) / (extents_y2 - extents_y1));
-      cairo_translate (temp_cr, - x_center, - y_center);
+      cairo_new_path (temp_cr);
+
+      int inner_radius;
+
+      inner_radius = MAX (0, outer_radius[ST_CORNER_TOPLEFT] - shadow_spec->spread);
+      if (inner_radius > 0)
+        {
+          cairo_arc (temp_cr,
+                     shrunk_extents_x1 + inner_radius,
+                     shrunk_extents_y1 + inner_radius,
+                     inner_radius,
+                     M_PI, 3 * M_PI / 2);
+        }
+
+      inner_radius = MAX (0, outer_radius[ST_CORNER_TOPRIGHT] - shadow_spec->spread);
+
+      cairo_line_to (temp_cr,
+                     shrunk_extents_x2 - inner_radius,
+                     shrunk_extents_y1);
+
+      if (inner_radius > 0)
+        {
+          cairo_arc (temp_cr,
+                     shrunk_extents_x2 - inner_radius,
+                     shrunk_extents_y1 + inner_radius,
+                     inner_radius,
+                     3 * M_PI / 2, 0);
+        }
+
+      inner_radius = MAX (0, outer_radius[ST_CORNER_BOTTOMRIGHT] - shadow_spec->spread);
+
+      cairo_line_to (temp_cr,
+                     shrunk_extents_x2,
+                     shrunk_extents_y2 - inner_radius);
+
+      if (inner_radius > 0)
+        {
+          cairo_arc (temp_cr,
+                     shrunk_extents_x2 - inner_radius,
+                     shrunk_extents_y2 - inner_radius,
+                     inner_radius,
+                     0, M_PI / 2);
+        }
+
+      inner_radius = MAX (0, outer_radius[ST_CORNER_BOTTOMLEFT] - shadow_spec->spread);
+
+      cairo_line_to (temp_cr,
+                     shrunk_extents_x1 + inner_radius,
+                     shrunk_extents_y2);
+
+      if (inner_radius > 0)
+        {
+          cairo_arc (temp_cr,
+                     shrunk_extents_x1 + inner_radius,
+                     shrunk_extents_y2 - inner_radius,
+                     inner_radius,
+                     M_PI / 2, M_PI);
+        }
+
+      cairo_close_path (temp_cr);
 
-      cairo_append_path (temp_cr, shadow_outline);
       cairo_fill (temp_cr);
       cairo_destroy (temp_cr);
 
@@ -1330,6 +1380,7 @@ st_theme_node_prerender_background (StThemeNode *node,
       paint_inset_box_shadow_to_cairo_context (node,
                                                box_shadow_spec,
                                                resource_scale,
+                                               radius,
                                                cr,
                                                interior_path ? interior_path
                                                              : outline_path);